import {
  h,
  computed,
  nextTick,
  onMounted,
  ref,
  watch,
  defineComponent,
  onUnmounted,
  reactive,
  VNode,
  PropType
} from "vue";
import {ElMessage, ElCard, ElButton, ElProgress, ElInputNumber, ElLoading, ElIcon} from "element-plus"
import {
  VideoPlay,
  Refresh,
  VideoPause,
  DArrowRight,
  DArrowLeft,
  CaretRight,
  CaretLeft,
  Close,
} from '@element-plus/icons-vue'
import {wsg2mapcoor} from '@/utils/gps/maptransform'
import {IsPtInPoly} from '@/utils/gps/inside'
import {timeFormat} from '@/utils/gps/format'
import {Point} from 'ol/geom'
import {Map, View, Feature} from 'ol'
import Overlay from 'ol/Overlay'
import LineString from 'ol/geom/LineString'
import sourceVector from 'ol/source/Vector'
import layerVector from 'ol/layer/Vector'
import {Circle, Fill, Stroke, Style, Icon, Text} from 'ol/style'
import startIconPng from '@/assets/gps/start_icon.png'
import endIconPng from '@/assets/car/end_icon.png'
import carbluePng from '@/assets/car/car_blue.png'
import stayMarkers from '@/assets/gps/stay_markers.png'
import alarmMarkers from '@/assets/gps/alarm.png'
import "@/styles/trajectory.css"
import {createPopup} from "@/utils/gps/createPopup";
import trajectoryInnerTemplate from "@/components/map-trajectory/tarjectoryInnerTemplate"
import {createLayers2, createMap} from "@/utils/ol/maptools";
import SourceVector from "ol/source/Vector";
import LayerVector from "ol/layer/Vector";

type SpotType = "stop" | "start" | "end"

export default defineComponent({
  name: "Trajectory",
  props: {
    // v-model 记录当前的播放位置
    modelValue: {
      type: Number,
      required: true,
      default: 0
    },
    // 加载函数，true为开启加载
    loading: {
      type: Boolean,
      default: false
    },
    // 控制面板 true为启用
    control: {
      type: String as PropType< "" | "simple" | "complex">,
      default: ""
    }
  },
  emits: ["update:modelValue"],
  setup(prop, {emit, expose}) {
    let map: Map
    let vectorLayer: layerVector<any>
    let iconLayer: layerVector<any>
    let loadingEl: any = null
    let popup: VNode | null
    const mapRef = ref()
    const trajectoryPopupRef = ref()
    const trajectoryLoadingRef = ref()

    let carSource
    const popupKey = ref("")

    // 播放速率
    const playSpeed = ref<number>(500)
    // 进度
    const percentage = ref<number>(0)
    const currentPosition = ref<{ [key: string]: any }>()
    const currentStep = ref<number>(0)
    const isPlay = ref<boolean>(false)
    const speed = ref(0)

    let carFeature: Feature
    let stepInterval: any = null

    const polylinePath = ref([])

    const record = reactive<{ position: any[] }>({
      position: []
    })

    const mapCoordinates = {
      travelPath: [],
      tripsPath: [],
      stopPosition: [],
      alarmsPosition: []
    }

    const currentPage = computed(() => {
      return (record.position.length > 0 ? currentStep.value + 1 : 0) + ' / ' + record.position.length
    })

    watch(() => prop.modelValue, (val) => {
      currentStep.value = val || 0
    }, {immediate: true, deep: true})
    watch(currentStep, (val) => {
      cruiseEvent()
      emit("update:modelValue", val)
    })

    watch(
        () => prop.loading, (value) => {
          if (value) {
            nextTick(() => {
              loadingEl = ElLoading.service({
                target: trajectoryLoadingRef.value,
                text: '生成数据中...',
                background: 'rgba(255,255,255,0.7)'
              })
            })
          } else {
            loadingEl?.close()
          }
        }, {immediate: true}
    )

    onMounted(() => {
      initMap()
    })

    onUnmounted(() => {
      clearInterval(stepInterval)
    })

    expose({
      init, removeLayer, handlePause, handlePlay
    })

    /**
     * 初始化地图
     */
    function initMap() {
      map = createMap(mapRef.value, createLayers2())
      map.on("pointermove", mapMovement)
    }

    /**
     * 重置数据
     */
    function handleReset() {
      record.position = []
    }

    /**
     * 获取数据
     */
    function init(data) {
      const {positions, stops, alarms, trips} = data
      record.position = positions
      if (vectorLayer) map.removeLayer(vectorLayer)
      if (iconLayer) map.removeLayer(iconLayer)
      mapCoordinates.stopPosition = stops.map((item: any) => {
        const {lng, lat} = wsg2mapcoor(item.longitude, item.latitude)
        return {
          lng,
          lat,
          time: timeFormat(item.duration),
          startTime: item.startTime
        }
      })
      mapCoordinates.alarmsPosition = alarms.map((item: any) => {
        const {lng, lat} = wsg2mapcoor(item.longitude, item.latitude)
        return {
          lng,
          lat,
          time: timeFormat(item.occurTime)
        }
      })
      currentPosition.value = positions?.[0]
      mapCoordinates.travelPath = positions.map((item: any) => {
        const {lng, lat} = wsg2mapcoor(item.longitude, item.latitude)
        return [lng, lat]
      })
      if (positions?.length) {
        createVectorLayer()
        createNewRoute(mapCoordinates.travelPath, "line")
        // trajectoryPath(mapCoordinates.travelPath)
      } else {

      }
    }

    let source: SourceVector

    function createVectorLayer(){
      // 矢量层
      if(!source) source = new SourceVector()
      // 图层
      if(!vectorLayer) {
        vectorLayer = new LayerVector()
        vectorLayer.setSource(source)
        map.addLayer(vectorLayer)
      }
    }

    function createNewRoute(polyline, id){
      const geometry = new LineString(polyline)
      console.log(polyline)
      const lineFeature = new Feature(geometry)
      lineFeature.setStyle(new Style({
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.6)'
        }),
        stroke: new Stroke({
          color: 'rgba(0,153,255, 0.6)',
          width: 8
        }),
        image: new Circle({
          radius: 7,
          fill: new Fill({
            color: '#0099FF'
          })
        })
      }))
      lineFeature.setId(id)
      source.addFeatures([lineFeature])
    }

    /**
     * 画轨迹
     * @param e
     */
    function trajectoryPath(e: any[]) {
      const polyline = e
      // 实例化图层
      let geometry = new LineString(polyline)
      let source = new sourceVector()
      // 绘制轨迹
      let LineFeature = new Feature(geometry)
      source.addFeature(LineFeature)

      vectorLayer = new layerVector({
        source,
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.6)'
          }),
          stroke: new Stroke({
            color: 'rgba(20, 155, 155, 0.8)',
            width: 6
          }),
          image: new Circle({
            radius: 7,
            fill: new Fill({
              color: '#0099FF'
            })
          })
        })
      })
      map.addLayer(vectorLayer)
      setMark(polyline)
    }

    /**
     * 画Marker点
     * @param e
     */
    function setMark(e: any[]) {
      let markers: any[] = [
        {
          po: e[0],
          img: startIconPng,
          name: 'start'
        },
        {
          po: e[e.length - 1],
          img: endIconPng,
          name: 'end'
        }
      ]
      // 添加停留点
      if (mapCoordinates.stopPosition.length > 0) {
        markers.push(
            ...mapCoordinates.stopPosition.map((item: any, index) => {
              return {
                po: [item.lng, item.lat],
                img: "https://gps.1688wxq.com/gps/icon/points/" + (index + 1),
                name: 'stop',
                time: item.time,
                startTime: item.startTime,
                index: index + 1
              }
            })
        )
      }
      // 添加报警点
      if (mapCoordinates.alarmsPosition.length > 0) {
        markers.push(
            ...mapCoordinates.alarmsPosition.map((item: any, index) => {
              return {
                po: [item.lng, item.lat],
                img: alarmMarkers,
                name: 'alarm',
                time: item.time,
                index: index + 1
              }
            })
        )
      }
      let isIcon: any[] = []
      markers.forEach((item: any) => {
        // 创建图标特性
        let iconFeature = new Feature({
          geometry: new Point(item.po),
        })
        iconFeature.setId(item.name + (item.index ? ("-" + item.index) : ""))
        // 创建图标样式
        iconFeature.setStyle(
            new Style({
              image: new Icon({
                // 定义图标锚点
                anchor: [0.5, 1],
                scale: 0.5,
                src: item.img
              })
            })
        )
        isIcon.push(iconFeature)
      })
      let vectorSource = new sourceVector({
        features: isIcon
      })
      // 图标添加进矢量容器
      carSource = vectorSource
      // 创建矢量图层
      iconLayer = new layerVector({
        source: vectorSource
      })
      map.addLayer(iconLayer)
      // 绘制车标
      timeMarker([record.position[0].longitude, record.position[0].latitude], 0, false)
      // 定位地图总心
      map.getView().setCenter(e[0])
    }

    /**
     * 遍历
     * @param v
     * @param rotation
     * @param status
     */
    function timeMarker(v: any[], rotation: number, status: boolean) {
      if (status) carSource.removeFeature(carFeature)
      const {lng, lat} = wsg2mapcoor(v[0], v[1])
      carFeature = new Feature({
        geometry: new Point([lng, lat])
      })
      carFeature.setId("car")
      carFeature.setStyle(
          new Style({
            image: new Icon({
              // 定义图标锚点
              anchor: [10, 18],
              anchorOrigin: 'bottom-left',
              anchorXUnits: 'pixels',
              anchorYUnits: 'pixels',
              rotation: (Math.PI / 180) * (rotation % 360),
              src: carbluePng
            })
          })
      )
      carSource.addFeature(carFeature)
    }

    /**
     * 判断小车是否在可视范围内
     * @param lat
     * @param lng
     */
    function isInside(lat: number, lng: number) {
      let isArr: any = map.getView().calculateExtent(map.getSize())
      if (
          !IsPtInPoly(lat, lng, [
            {longitude: isArr[2], latitude: isArr[1]},
            {longitude: isArr[0], latitude: isArr[1]},
            {longitude: isArr[0], latitude: isArr[3]},
            {longitude: isArr[2], latitude: isArr[3]}
          ])
      )
        map.getView().setCenter([lng, lat])
    }

    // 正则
    const regex = new RegExp("^stop|start|end|car");

    /**
     * map鼠标移动事件
     * 判断是否创建弹窗
     * @param event
     */
    function mapMovement(event) {
      const pixel = map.getEventPixel(event.originalEvent)
      const feature = map.forEachFeatureAtPixel(pixel, (feature) => feature)
      if (feature === undefined) {
        if (popup) {
          popup?.component?.exposed?.closeWindow()
          popup = null
          popupKey.value = ""
        }
        map.getTargetElement().style.cursor = ""
        return
      }
      const id: string = feature.getId() as string || ""
      map.getTargetElement().style.cursor = regex.test(id) ? "pointer" : ""
      const keys = id.split("-")
      if (keys[0] !== "stop") return
      if (popupKey.value === id) return
      let data: any
      data = mapCoordinates.stopPosition[parseInt(keys[1]) - 1]
      if (keys[0] === "stop") {
        data && (data.serialNumber = parseInt(keys[1]))
      }
      showPopup(event.coordinate, data, keys[0])
      popupKey.value = id
    }

    /**
     * 显示弹窗
     * 内部由createPopup()创建一个vNode，将其变为Overlay，并添加到map上
     * @param coordinate 坐标
     * @param data 数据
     * @param type
     */
    function showPopup(coordinate, data, type: SpotType) {
      popup = createPopup({
        header: (close) => h("div", {
          class: "popup_close",
          style: {
            position: "absolute",
            top: "5px",
            right: "5px"
          },
          onClick: close
        }, h(ElIcon, {
          size: 20
        }, () => h(Close))),
        default: () => h(trajectoryInnerTemplate, {
          type: type,
          data: data
        })
      }, {
        target: trajectoryPopupRef.value,
        mask: false,
        rootElStyle: "position: static; transform: none; margin: 0; width: 200px"
      })

      let anchor = new Overlay({
        element: popup.el as any,
        positioning: 'bottom-center',
        stopEvent: true,
        offset: [0, -10]
      });
      map.addOverlay(anchor);
      anchor.setPosition(coordinate)

      // anchor.getElement().addEventListener('mouseenter', function() {
      //   console.log('鼠标悬浮在Overlay上');
      // })
      //
      // anchor.getElement().addEventListener('mouseleave', function() {
      //   console.log('鼠标离开Overlay');
      // })
    }

    function cruiseEvent() {
      isPlay.value = true
      currentPosition.value = record.position[currentStep.value]
      timeMarker([currentPosition.value?.longitude, currentPosition.value?.latitude], currentPosition.value?.course, true)
      isInside(currentPosition.value?.latitude, currentPosition.value?.longitude)
      speed.value = record.position[currentStep.value].speed
      percentage.value = parseFloat(((currentStep.value / record.position.length) * 100).toFixed(1))
    }

    /**
     * 开始播放
     */
    function handlePlay() {
      console.log("开始播放");
      if (record.position.length === 0) return ElMessage.warning('无法播放')
      stepInterval = setInterval(() => {
        if (currentStep.value < record.position.length - 1) {
          currentStep.value++
        } else {
          percentage.value = 100
          handlePause()
        }
      }, playSpeed.value)
    }

    /**
     * 暂停播放
     */
    function handlePause() {
      console.log("暂停");
      isPlay.value = false
      clearInterval(stepInterval)
    }

    /**
     * 重置播放
     */
    function handleRefresh() {
      currentStep.value = 0
      percentage.value = 0
      currentPosition.value = record.position[0]
      polylinePath.value.splice(0, polylinePath.value.length)
    }

    /**
     * 上一步
     */
    function handlePrev() {
      if (currentStep.value > 0 && currentStep.value <= record.position.length) currentStep.value--
      polylinePath.value.splice(currentStep.value, polylinePath.value.length)
      adjust()
    }

    /**
     * 下一步
     */
    function handleNext() {
      if (currentStep.value < record.position.length) currentStep.value++
      adjust()
    }

    function adjust() {
      const start = record.position[currentStep.value]
      currentPosition.value = start
      // 获取速度表
      speed.value = start?.speed
      // 获取百分比
      percentage.value = parseFloat(((currentStep.value / record.position.length) * 100).toFixed(1))
      const rotation = start?.course
      timeMarker([start.longitude, start.latitude], rotation, true)
    }

    function removeLayer() {
      map.removeLayer(vectorLayer)
      map.removeLayer(iconLayer)
    }

    // 媒体相关
    const innerRef = ref()

    // 已播放进度
    const playedProgress = computed(() => {
      return `width: ${percentage.value}%`
    })

    // 已加载进度
    const loadedProgress = computed(() => {
      return `width: ${100}%`
    })

    // 进度条实际宽度
    const progressBarWidth = computed(() => {
      return innerRef.value?.offsetWidth
    })

    function Complex(){
      return <ElCard class="tool-window">
        <div style="margin-bottom: 15px">
          播放速度
          <ElInputNumber modelValue={playSpeed.value} precision={0} min={100} max={5000}
                         step-strictly step={100} style="width: 150px"></ElInputNumber>
          毫秒
        </div>
        <ElProgress text-inside stroke-width={15} percentage={percentage.value}></ElProgress>
        <div style="margin: 10px 0">轨迹时间：{ currentPosition.value?.deviceTime }</div>
        <div style="margin-bottom: 10px">运动速度：{ (speed.value * 1.852).toFixed(2) } Km/h</div>
        {
          !isPlay.value? <ElButton type="primary" icon={VideoPlay} onClick={ handlePlay }></ElButton> :
              <ElButton type="primary" icon={VideoPause} onClick={ handlePause }></ElButton>
        }
        <ElButton type="danger" icon={Refresh} onClick={handleRefresh}></ElButton>
        <ElButton type="success" disabled={currentStep.value === 0} icon={DArrowLeft} onClick={handlePrev}></ElButton>
        <span class="pageNum">{ currentPage.value }</span>
        <ElButton type="success"
                  disabled={currentStep.value === record.position.length - 1 || record.position.length === 0}
                  icon={DArrowRight}
                  onClick={handleNext}></ElButton>
      </ElCard>
    }

    function Simple() {
      return <div class="tool-window">
        <div class={`btn ${currentStep.value === 0 ? "disabled" : ""}`}
             onClick={handlePrev}>
          <ElIcon size={22} color="rgb(64, 158, 255)"><CaretLeft></CaretLeft></ElIcon>
        </div>
        {
          !isPlay.value ? <div class="btn" onClick={handlePlay}>
                <ElIcon size={22} color="rgb(64, 158, 255)"><VideoPlay></VideoPlay></ElIcon>
              </div>
              :
              <div class="btn" onClick={handlePause}>
                <ElIcon size={22} color="rgb(64, 158, 255)"><VideoPause></VideoPause></ElIcon>
              </div>
        }
        <div
            class={`btn ${currentStep.value === record.position.length - 1 || record.position.length === 0 ? "disabled" : ""}`}
            onClick={handleNext}>
          <ElIcon size={22} color="rgb(64, 158, 255)"><CaretRight></CaretRight></ElIcon>
        </div>
        {/*<ElButton type="danger" icon={Refresh} onClick={handleRefresh}></ElButton>*/}
        <div class="player_progress">
          <div ref={innerRef} class="player_progress__inner">
            <div class="player_progress__load" style={loadedProgress.value}></div>
            <div class="player_progress__play" style={playedProgress.value}>
              <i ref="dotRef" class="player_progress__dot"></i>
            </div>
          </div>
        </div>
      </div>
    }

    return () => <div class="trajectory">
      <div ref={mapRef} class="map-fence"></div>
      <div ref={trajectoryPopupRef}></div>
      {
        prop.control === "simple" ? <Simple /> : prop.control === "complex"? <Complex/> : null
      }
      <div ref={trajectoryLoadingRef} class="trajectory_loading"></div>
    </div>
  }
})
